# [二] Spring 程序入口和xml解析

# [1] Spring 源码下载

1、git clone --branch v5.1.3.RELEASE https://gitee.com/Z201/spring-framework.git。

2、gradle 下载,gradle 要 JDK8 的版本。

3、到下载的 spring 源码路径执行 gradle 命令。

gradlew :spring-oxm:compileTestJava

4、用 idea 打开 spring 源码工程,在 idea 中安装插件 kotlin,重启 idea 5、把编译好的源码导入到工程中。

# [2] 把源码导入到工程

image-20200107180352744

image-20200107180529223

image-20200107180558663

# [3] 导入 jar 依赖

Spring 中最核心的 4 个 jar

  • Spring-beans
  • Spring-core
  • Spring-context
  • Spring-expression

一个最最简单的 spring 工程,理论上就只需要一个 jar 就够了

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>

Spring-context 包本身就依赖了,Spring-aop,Spring-beans,Spring-core 包

一个空的 spring 工程是不能打印日志的,要导入 spring 依赖的日志 jar

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>LATEST</version>
</dependency>

# [4] Spring 容器加载方式

  • 1、类路径获取配置文件
ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring.xml");
  • 2、文件系统路径获取配置文件[绝对路径]
ApplicationContext applicationContext = new
FileSystemXmlApplicationContext("E:\\idea\\springdemo\\spring.xml");
  • 3 、 无 配 置 文 件 加 载 容 器
ApplicationContext applicationContext = new
AnnotationConfigApplicationContext("com.xx.jack");
  • 4、springboot 加载容器
ApplicationContext applicationContext = new EmbeddedWebApplicationContext();

# [5] Spring 容器加载核心方法

AbstractApplicationContext.refresh()方法 refresh()方法是 spring 容器启动过程中的核心方法,spring 容器要加载必须执行该方法。

# [6] Xml 流程分析

# [7] 自定义标签解析

  • 1、获取自定义标签的 namespace 命令空间,例如:
http://www.springframework.org/schema/context
String namespaceUri = getNamespaceURI(ele);
  • 2、根据命令空间获取 NamespaceHandler 对象

NamespaceUri 和NamespaceHandler 之间会建立一个映射,spring 会从所有的spring jar 包中扫描 spring.handlers 文件,建立映射关系。

NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve( namespaceUri);
Map<String, Object> handlerMappings = getHandlerMappings();
Object handlerOrClassName = handlerMappings.get(namespaceUri);
  • 3、反射获取 NamespaceHandler 实例
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
  • 4、调用 init 方法
namespaceHandler.init();
  • 5、调用 parse 方法
handler.parse(ele, new ParserContext(this.readerContext,
this, containingBd))

扩展

spring.handler文件其实就是 namespaceUri 和类的完整限定名的映射。